package com.sp.business.normalization.impl.mf2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class replicates the behavior of Lua tables
 * (http://www.lua.org/pil/2.5.html). Lua tables are unique data structures in
 * that they are both key value maps and arrays. Element without keys are stored
 * in order, elements with integer keys (ie '[259]=true') are stored in the
 * array at location 259.
 * 
 * Note the array is '1' based, not '0' as most every other language.
 * 
 * @author mtaylor
 * 
 */
public class Mf2Object {
    Map<String, Object> map = new HashMap<String, Object>();
    List<Object> list = new ArrayList<Object>();
    String label;

    Object tempKey;
    Object tempValue;

    // Mf2Parser builds these up as we go, it adds the key
    // and value. This method adds key, value to the array OR the map
    void commit() {
        if (tempKey == null && tempValue == null) {
            return;
        } else if (tempKey == null) {
            list.add(tempValue);
        } else if (tempKey instanceof Integer) {
            int index = (Integer) tempKey;
            while (list.size() < index)
                list.add(null);
            list.set(index - 1, tempValue); // count begins at 1
        } else {
            map.put((String) tempKey, tempValue);
        }
        tempKey = null;
        tempValue = null;
    }

    Object get(String key) {
        return map.get(key);
    }

    Object get(Integer index) {
        if (index >= list.size())
            return null;
        return list.get(index);
    }

    public static void printMf2Object(Mf2Object object, String indent) {
        int counter = 1;
        if (object.label != null) {
            System.out.println("Object: " + object.label);
        }
        for (Object o : object.list) {
            if (o == null) {
                counter++;
                continue;
            }
            if (o instanceof String || o instanceof Integer
                    || o instanceof Boolean) {
                System.out.println(indent + counter + ": " + o.toString());
            } else {
                System.out.println(indent + counter + ": ");
                printMf2Object((Mf2Object) o, indent + "  ");
            }
            counter++;
        }
        for (String key : object.map.keySet()) {
            // System.out.println(indent + key + ": " + object.map.get(key));
            Object o = object.map.get(key);
            if (o == null)
                continue;
            if (o instanceof String || o instanceof Integer
                    || o instanceof Boolean) {
                System.out.println(indent + key + ": " + o.toString());
            } else {
                System.out.println(indent + key + ":");
                printMf2Object((Mf2Object) o, indent + "  ");
            }
        }
    }
    
    public static Object find(Mf2Object mf2Obj, String path) {
        Object result = mf2Obj;
        try {
            String[] tokens = path.split(":");
            for(String t : tokens) {
                Integer index = asInt(t);
                if(index != null) {
                    result = ((Mf2Object)result).get(index);
                } else {
                    result = ((Mf2Object)result).get(t);
                }
            }
        } catch(Exception e) {
            return null;
        }
        return result;
    }
    
    public static Integer asInt(String token) {
        try {
            return Integer.valueOf(token);
        } catch(Exception e) {
            return null;
        }
    }
}
